package com.zf.fastexcel.utils.handler;

import cn.idev.excel.write.handler.SheetWriteHandler;
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Workbook;

import java.util.Objects;


/**
 * 由于模板填充时，无法直接修改填充后的sheet的名字，因此定义处理来修改，该类也适用于非模板填充修改sheet名字。
 * 一般非模板填充时，可以直接指定sheet名字，不需要使用该处理器，但是也是可以使用的。
 *
 * <pre>
 * 使用方式：
 * 方式1、使用模板填充时，可以在读取模板sheet的时候就修改sheet的名称，将其注册到 ExcelWriter 中，如果有多个模板要修改则可以注册多个，
 *              但是每一次填充sheet时，都会调用ExcelWriter中的所有的处理器，效率较低：
 *      {@code
 *          ExcelWriter writer = FastExcel.write(OutputStream)
 *                                          .registerWriteHandler(new CustomSheetNameWriteHandler(0, "修改后的名字"))
 *                                          .registerWriteHandler(new CustomSheetNameWriteHandler(1, "修改后的名字1"))
 *                                          .withTemplate(templateInputStream()).build();
 *      }
 *
 * 方式2、使用模板填充时，可以在 WriteSheet 中注册该处理器，填充对应的sheet时就只调用该 WriteSheet 中注册的处理器，不会调用其他 WriteSheet 中注册的处理器，推荐使用该方式完成sheet名字的修改
 *      {@code
 *          // 读取模板文件
 *         ExcelWriter writer = FastExcel.write(OutputStream).withTemplate(templateInputStream).build();
 *
 *         // 构建一个sheet, 默认是第0个sheet, 要想完成 fill 操作，需要和模板文件中模板所在的 sheet位置/名字 保持一致，否则没有办法完成填充
 *         WriteSheet sheet = FastExcel
 *                 // sheet位置/名字，
 *                 // 如果写 sheet位置，则必须是已经存在的sheet的位置 或者是 0，否则报越界错误
 *                 .writerSheet(0)
 *                 // 定义一个处理器，修改sheet的名字
 *                 .registerWriteHandler(new CustomSheetNameWriteHandler(0, "修改后的名字"))
 *                 .build();
 *          //填充数据
 *         HashMap<String, Object> data1 = new HashMap<>();
 *         data1.put("name", "张三");
 *         data1.put("age", 22);
 *         writer.fill(data1, sheet);
 *      }
 * 3、不使用模板填充时，执行情况和上面的情况是一致
 * </pre>
 */
public class CustomSheetNameWriteHandler implements SheetWriteHandler {

    private final Integer sheetNo;
    private final String newSheetName;

    public CustomSheetNameWriteHandler(Integer sheetNo, String newSheetName) {
        if (Objects.isNull(sheetNo) || Objects.isNull(newSheetName)) {
            throw new IllegalArgumentException("sheet位置和名字都不能为 null");
        }
        this.newSheetName = newSheetName;
        this.sheetNo = sheetNo;
    }

    /**
     * 在Sheet创建后立即调用该方法
     */
    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 获取workbook, writeWorkbookHolder.getWorkbook() 仅用于写入。但是如果用于读取模板中的数据时，07 版本中可能没有数据。
        // 03:HSSFWorkbook
        // 07:SXSSFWorkbook，对 XSSFWorkbook 的流式处理
        Workbook workbook = writeWorkbookHolder.getWorkbook();

        // 获取workbook, writeWorkbookHolder.getCachedWorkbook() 如果需要读取模板中的数据时务必使用此方法，一定可以得到workbook，07 版本中也会有数据。
        // 03:HSSFWorkbook
        // 07:XSSFWorkbook
        // Workbook workbook = writeWorkbookHolder.getCachedWorkbook();
        // Workbook workbook = writeSheetHolder.getCachedSheet().getWorkbook();

        // 修改sheet的名字
        workbook.setSheetName(sheetNo, newSheetName);

        // 获取创建后的sheet，可以做些其他的操作，这两个方法和上面的情况一致
        // Sheet sheet = writeSheetHolder.getSheet();
        // Sheet sheet = writeSheetHolder.getCachedSheet();
    }

}